package helper.scxml.strategy

import helper.base.A2LHM
import helper.base.A2Tuple
import helper.base.BaseTypeHelper.toIntRange
import helper.base.LHMHelper.A2LHMExpand.touch
import helper.base.LHMHelper.LHMExpand.toA2LHM
import helper.base.string.ToLStringHelper.IToL1String
import helper.base.string.ToLStringHelper.IToL2String
import helper.base.string.ToLStringHelper.preTabAndTrim
import helper.base.string.ToStrHelper.IToStr
import helper.base.string.ToStrHelper.TabStringUnit.Companion.makeTabStringUnit
import helper.scxml.scxml2.zone.t2.ConfigHelper.Config
import helper.scxml.strategy.StrategyHelper.TimedEventHelper.ITimedEvent
import helper.scxml.strategy.StrategyHelper.TimedEventHelper.TimedEvent
import helper.scxml.strategy.StrategyHelper.TimedEventHelper.getMTimedEvent
import helper.scxml.strategy.StrategyHelper.TimedEventHelper.getTimedEventWeightLHM
import helper.scxml.strategy.TotalStrategyHelper.E154.toL1String
import helper.scxml.strategy.TotalStrategyHelper.E154.toL2String

object TotalStrategyHelper {
    class REWTuple(
        val intRange: IntRange,
        val event: String,
        val weight: Double,
    ) {
        companion object {
            fun makeREWTuple(
                intRange: IntRange,
                event: String,
                weight: Number,
            ): REWTuple {
                return REWTuple(
                    intRange,
                    event,
                    weight.toDouble(),
                )
            }

            fun makeREWTuple(
                int: Int,
                event: String,
                weight: Number,
            ): REWTuple {
                return makeREWTuple(
                    int.toIntRange(),
                    event,
                    weight.toDouble(),
                )
            }
        }

        operator fun component1() = intRange
        operator fun component2() = event
        operator fun component3() = weight
    }

    class KREWsTuple(
        val key: String,
        val aREWs: List<REWTuple>,
    ) {
        companion object {
            fun makeKREWsTuple(
                key: String,
                aREWs: List<REWTuple>,
            ): KREWsTuple {
                return KREWsTuple(key, aREWs)
            }
        }
    }

    class KREWTuple(
        val key: String,
        val intRange: IntRange,
        val event: String,
        val weight: Double,
    ) {
        companion object {
            fun makeKREWTuple(
                key: String,
                intRange: IntRange,
                event: String,
                weight: Number,
            ): KREWTuple {
                return KREWTuple(
                    key,
                    intRange,
                    event,
                    weight.toDouble(),
                )
            }

            fun makeKREWTuple(
                key: String,
                int: Int,
                event: String,
                weight: Number,
            ): KREWTuple {
                return makeKREWTuple(
                    key,
                    int.toIntRange(),
                    event,
                    weight.toDouble(),
                )
            }
        }

        operator fun component1() = key
        operator fun component2() = intRange
        operator fun component3() = event
        operator fun component4() = weight
    }

    interface IZoneTotalStrategy {
        fun getMsTimeEventChoiceList(config: Config): ArrayList<TimedEvent>
    }

    class EDoubleLHM<E> : A2LHM<E, Double>() {
        companion object {
            fun <E> makeEDoubleLHM(): EDoubleLHM<E> {
                return EDoubleLHM()
            }
        }
    }

    interface ISNode : IToStr, IToL1String, IToL2String

    interface I2SNode : IToStr, IToL1String, IToL2String

    open class SNode : ISNode, I2SNode {
        companion object {
            fun makeSNode() = SNode()
        }
    }

    data class LeafSNode(
        val eventDPLHM: A2LHM<ITimedEvent, Double>,
    ) : ISNode, I2SNode {
        companion object {
            fun makeLeafSNode(
                eventDPLHM: A2LHM<ITimedEvent, Double>
            ): LeafSNode {
                return LeafSNode(eventDPLHM)
            }

            fun makeLeafSNode(
                vararg pairs: A2Tuple<ITimedEvent, Double>
            ): LeafSNode {
                return makeLeafSNode(
                    pairs.toA2LHM()
                )
            }
        }

        object Expand {
            fun List<LeafSNode>.getTimeEventChoice(): TimedEvent? {
                return this.map {
                    it.eventDPLHM
                }.getMTimedEvent()
            }

            fun List<LeafSNode>.getTimeEventChoiceWeightLHM(): A2LHM<TimedEvent, Double> {
                return this.map {
                    it.eventDPLHM
                }.getTimedEventWeightLHM()
            }
        }

        fun getTimeEventChoice(): TimedEvent? {
            return eventDPLHM.getMTimedEvent()
        }

        fun getTimeEventChoiceWeightLHM(): A2LHM<TimedEvent, Double> {
            return eventDPLHM.getTimedEventWeightLHM()
        }

        override fun toStr(tabNum: Int): String {
            val sb = StringBuilder()
            val tsu = makeTabStringUnit(tabNum)
            sb.append("${tsu.tabNumStr0}LeafSNode.eventDPLHM=\n")
            eventDPLHM.touch { t, u ->
                sb.append("${tsu.tabNumStr1}${t.toL1String()}\t${u}\n")
            }
            return sb.toString()
        }

        override fun toL1String(): String {
            val sb = StringBuilder()
            sb.append("LeafSNode(")
            sb.append("eventDPLHM=${eventDPLHM.toL1String()}")
            sb.append(")")
            return sb.toString()
        }

        override fun toL2String(): String {
            val sb = StringBuilder()
            sb.append("LeafSNode(\n")
            sb.append("\teventDPLHM=${eventDPLHM.toL2String().preTabAndTrim()}\n")
            sb.append(")")
            return sb.toString()
        }
    }

    object E154 {
        fun A2LHM<ITimedEvent, Double>.toL1String(): String {
            val sb = StringBuilder()
            sb.append("A2LHM(size=${size})=[")
            this.forEach { (t, u) ->
                sb.append("${t.toL1String()}=${u},")
            }
            sb.append("]")
            return sb.toString()
        }

        fun A2LHM<ITimedEvent, Double>.toL2String(): String {
            val sb = StringBuilder()
            sb.append("A2LHM(size=${size})=[\n")
            this.forEach { (t, u) ->
                sb.append("\t${t.toL1String()}=${u}\n")
            }
            sb.append("]")
            return sb.toString()
        }
    }
}